﻿using System;
using System.Web;
using System.Web.Hosting;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.IO;
using System.Collections.Generic;

using SBPweb.Modules.Modularity;

namespace SBPweb.Services.Base
{
    public class CustomServiceHandler : VirtualPathProvider, IHttpHandlerFactory
    {

        #region Private fields

        private WebServiceHandlerFactory pWSHF = new WebServiceHandlerFactory();
        private Dictionary<string, ServiceEntry> pDictServices = new Dictionary<string, ServiceEntry>();

        #endregion

        #region Constructor logic

        public CustomServiceHandler()
        {
            HostingEnvironment.RegisterVirtualPathProvider(this);
        }

        #endregion

        #region Methods

        public ServiceBase GetService(HttpContext context)
        {
            string moduleName = GetModuleNameFromContext(context);
            ServiceEntry serviceEntry;
            lock (pDictServices)
            {
                if (!pDictServices.ContainsKey(moduleName))
                {
                    serviceEntry = InitializeServiceEntry(context);
                    pDictServices.Add(moduleName, serviceEntry);
                }
                else
                {
                    serviceEntry = pDictServices[moduleName];
                    if (!serviceEntry.IsInitialized)
                    {
                        throw new SystemException("Service has been previously shut down!");
                    }
                }
            }
            ServiceBase service = serviceEntry.CreateServiceInstance();

            return service;
        }

        public override bool FileExists(string virtualPath)
        {
//            if (File.Exists(HostingEnvironment.MapPath(virtualPath)))
//            {
//                return false;
//            }
            string name = GetModuleNameFromASMX(virtualPath);
            lock (pDictServices)
            {
                return pDictServices.ContainsKey(name);
            }
        }

        public override VirtualFile GetFile(string virtualPath)
        {
//            if (File.Exists(HostingEnvironment.MapPath(virtualPath)))
//            {
//                return null;
//            }
            string name = GetModuleNameFromASMX(virtualPath);
            lock (pDictServices)
            {
                ServiceEntry serviceEntry = pDictServices[name];
                return new VirtualServiceFile(virtualPath, serviceEntry.CreateServiceInstance());
            }
        }
        
        #region IHttpHandlerFactory Members

        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
        {
            WebService service;
            try
            {
                service = GetService(context);
            }
            catch (Exception ex)
            {
                throw new FileNotFoundException(url, ex);
            }
            IHttpHandler handler = pWSHF.GetHandler(service.Context, requestType, url.Replace(".ashx", ".asmx"), pathTranslated.Replace(".ashx", ".asmx"));
            return handler;
        }

        public void ReleaseHandler(IHttpHandler handler)
        {
            pWSHF.ReleaseHandler(handler);
        }

        #endregion

        #region Private helper functions

        private string GetModuleNameFromASHX(string path)
        {
            string ext = ".ashx";
            string ret = path.Substring(1);
            int pos = ret.IndexOf(ext);
            if (pos >= 0)
            {
                return ret.Substring(0, pos);
            }
            return ret;
        }

        private string GetModuleNameFromASMX(string path)
        {
            string ext = ".asmx";
            string ret = path.Substring(1);
            int pos = ret.IndexOf(ext);
            if (pos >= 0)
            {
                return ret.Substring(0, pos);
            }
            return ret;
        }

        private string GetModuleNameFromContext(HttpContext context)
        {
            return GetModuleNameFromASHX(context.Request.Url.LocalPath);
        }

        private ServiceEntry InitializeServiceEntry(HttpContext context)
        {
            string moduleName = GetModuleNameFromContext(context);
            ModuleLoader loader = context.Application["ModuleLoader"] as ModuleLoader;
            if (loader == null)
            {
                throw new ArgumentNullException("Module loader has not been initialized!");
            }
            /*
            if (!loader.Modules.ContainsKey(moduleName))
            {
                string dllName = moduleName.Substring(0, moduleName.LastIndexOf("."));
                FileInfo fI = new FileInfo(string.Format("{0}{1}{2}.dll", context.Request.PhysicalApplicationPath, "Modules\\", dllName));
                ModuleDescriptor md = ModuleDescriptor.CreateInstance(fI);
                ModuleInfo mI = new ModuleInfo(md, false, true, false);
                loader.LoadModule(mI);
            }
            */
            ServiceEntry serviceEntry = (ServiceEntry)loader.Modules[moduleName];
            if (!serviceEntry.IsInitialized)
            {
                serviceEntry.Initialize();
            }
            return serviceEntry;
        }

        #endregion

        #endregion

    }

}
